﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using AvalonTycoonMansion.Shared.Isometric;
using AvalonTycoonMansion.Shared.Library;
using AvalonTycoonMansion.Shared.Promotion;
using ScriptCoreLib;
using ScriptCoreLib.Shared.Avalon.Extensions;
using ScriptCoreLib.Shared.Avalon.Tween;
using ScriptCoreLib.Shared.Lambda;
//using Bulldog.Client.Promotion.Controls;

namespace AvalonTycoonMansion.Shared
{
    [Script]
    public class OrcasAvalonApplicationCanvas : Canvas
    {
        public const int DefaultWidth = Bulldog.Promotion.Games.AvalonTycoonMansion.Width;
        public const int DefaultHeight = Bulldog.Promotion.Games.AvalonTycoonMansion.Height;


        // references
        // http://www.flashrolls.com/skill-games/Big-Mansion-Flash-Game.htm
        // http://www.vaplay.com/game/21495/Mansion-Impossible.html
        // http://users.tt-forums.net/jfs/
        // http://www.transporttycoon.net/mp3/
        // http://users2.tt-forums.net/ttdur/ttdur.htm
        // http://www.tt-foundry.com/sets/FIRS/schema/graphics
        // http://www.tt-terminal.co.uk/downloads.shtml
        // http://users.tt-forums.net/narrowgauge/
        // http://grfcrawler.tt-forums.net/
        // http://www.tt-foundry.com/
        // http://george.zernebok.net/newgrf/t2m/newtoyland.html
        // http://tt-foundry.com/sets/heavy_equipment
        // http://www.tt-forums.net/viewtopic.php?f=26&t=27376
        // http://users.skynet.be/florisjan/ttd/ttrs.html

        public Action<int> SetHighscore;

        public TycoonStatusbar Statusbar;

        public Action ToFullscreen;

        public OrcasAvalonApplicationCanvas()
        {
            var Music = new AudioLoop
            {
                Volume = 0.02,

                Enabled = true,
                Loop = (KnownAssets.Path.Assets + "/JAZZHOP1.mp3"),

            };

            Width = DefaultWidth;
            Height = DefaultHeight;

            //this.ClipToBounds = true;
            this.Background = Brushes.Black;

            var Content = new Canvas { Width = DefaultWidth, Height = DefaultHeight }.AttachTo(this);

            var Playground = new IsometricContainer(
                DefaultWidth, 
                DefaultHeight, 
                
                25, 25, 
                false).AttachContainerTo(Content);


            var Instructions = new Canvas { Width = DefaultWidth, Height = DefaultHeight }.AttachTo(Content);

            var Builder = new PlaygroundBuilder
            {
                Playground = Playground,
                Descriptions = new KnownTileDescriptions()
            };

            var PropertyManager = new PropertyManager(Builder.Playground);

            Playground.Fill(Builder.Descriptions.Grass);


            Builder.RaiseLand(0, 0, Builder.Playground.SizeX - 1, 17);
            Builder.RaiseLand(1, 1, Builder.Playground.SizeX - 3, 9);
            Builder.RaiseLand(2, 2, Builder.Playground.SizeX - 5, 4);
            Builder.RaiseLand(1, 10, 6, 5, 1);
            Builder.RaiseLand(13, 20, 3, 4);

            var TrashArea = Playground.Where(k => k.Description == Builder.Descriptions.Grass);


            Builder.Descriptions.RoughLand.BuildTo(TrashArea.Randomize().Take(30));
            Builder.Descriptions.WildGrass.BuildTo(TrashArea.Randomize().Take(50));




            Builder.RailsX(4);
            Builder.RoadY(10);
            Builder.RoadY(16);
            Builder.RoadX(19);
            Builder.RoadX(15);
            Builder.RoadX(8);




            Builder.AddBusX(5.5, 18.3);
            Builder.AddBusX(15.5, 7.5);
            Builder.AddBusX(18.5, 14.3);

            // no build animation yet for these houses
            //Playground[9, 17].Description = Builder.Descriptions.House4;
            //Playground[17, 17].Description = Builder.Descriptions.House3;

            Playground[12, 7].Description = Builder.Descriptions.HeadQuarter;

            var HQProperty = new PropertyManager.AvailableProperty(PropertyManager)
            {
                Tile = Playground[12, 7],
                //Analytic = new PropertyValueAnalytic(),
                //Value = 8999,
                //Value = 1,
                Value = 10000,
            };



            Playground[14, 21].Description = Builder.Descriptions.Radio1a;

            //new PropertyManager.AvailableProperty(PropertyManager)
            //{
            //    Tile = Playground[14, 21],
            //    Value = 2111,
            //};


            #region special fx
            Playground[17, 13].Description = Builder.Descriptions.GrassDirtBlock;
            Playground[18, 12].Description = Builder.Descriptions.GrassDirtBlock;
            Playground[19, 12].Description = Builder.Descriptions.GrassDirtBlock;
            Playground[20, 12].Description = Builder.Descriptions.GrassDirtBlock;

            Playground[18, 13].Description = Builder.Descriptions.Grass101;

            Playground[19, 13].Altitude -= 8;
            Playground[19, 13].Description = Builder.Descriptions.RoughLand;

            Playground[20, 13].Description = Builder.Descriptions.Grass106;
            #endregion




            #region ConstructionYard
            var ConstructionYard =
                //Playground.Select(11, 10, 1, 5)
                Playground.Select(11, 10, 5, 5)
                .Concat(Playground.Select(7, 10, 3, 5))
                .Concat(Playground.Select(17, 10, 1, 5))
                .Concat(Playground.Select(11, 17, 5, 2))
                ;



            #endregion

            //Builder.Descriptions.DirtGrassGrass.BuildTo(ConstructionYard);





            Builder.DeadTree +=
                delegate
                {
                    new PlaygroundBuilder.Tree1(TrashArea.Random()).SetFrame(0);
                };

            this.Statusbar = new TycoonStatusbar
            {
                BankAccount = 200,
                Calendar = 1
            };

            Statusbar.AttachContainerTo(Playground.Overlay);


            Builder.BeforeVisualizeCost +=
                (cost, tile) =>
                {
                    Statusbar.BankAccount += cost;
                };



            TrashArea.Randomize().Take(30).ForEach(Builder.BuildTree1);
            TrashArea.Randomize().Take(10).ForEach(Builder.BuildTree1);
            //TrashArea.Randomize().Take(5).ForEach(Builder.BuildTree1);


            700.AtInterval(
                delegate
                {
                    Builder.Animate();
                }
            );


            #region jsc logo
            var LogoContainer = new Canvas { Width = DefaultWidth, Height = DefaultHeight };
            var Logo = new Image
            {
                Source = (KnownAssets.Path.Assets + "/jsc.png").ToSource(),
                Width = 64,
                Height = 64
            }.AttachTo(LogoContainer);

            Action CenterLogo = delegate
            {
                LogoContainer.SizeTo(this.Width, this.Height);
                Logo.MoveTo(this.Width - 72, this.Height - 72);
            };

            this.SizeChanged +=
                delegate
                {
                    CenterLogo();
                };

            CenterLogo();

            LogoContainer.AttachTo(Content);
            #endregion





            #region Mouse
            var MouseContainer = new TycoonMouse().AttachContainerTo(Content);


            var TouchOverlay = new Canvas
            {
                Width = DefaultWidth,
                Height = DefaultHeight,
                Background = Brushes.Yellow,
                Opacity = 0,
                Cursor = Cursors.None
            }.AttachTo(this);
            MouseContainer.Hide();

            this.SizeChanged +=
                delegate
                {
                    TouchOverlay.SizeTo(this.Width, this.Height);
                };

            var DelayedMouseEvents = TouchOverlay.ToDelayedMouseEvents();

            #region show mouse while inside bounds
            DelayedMouseEvents.MouseEnter +=
                delegate
                {
                    MouseContainer.Show();
                };

            DelayedMouseEvents.MouseLeave +=
                delegate
                {
                    MouseContainer.Hide();
                    PropertyManager.Selection = null;
                };
            #endregion

#if DEBUG
            var MouseSprite = new IsometricContainer.Sprite(Playground, 8, 8);
            MouseSprite.Container.Background = Brushes.Red;

            var MouseSprite2 = new IsometricContainer.Sprite(Playground, 8, 8);
            MouseSprite2.Container.Background = Brushes.Yellow;
#endif



            #region mouse handler
            var IsometricTouchOverlay = new IsometricOverlay(Builder.Playground);

            IsometricTouchOverlay.AttachContainerTo(TouchOverlay);

            this.SizeChanged +=
                delegate
                {
                    IsometricTouchOverlay.Container.SizeTo(this.Width, this.Height);
                };

            IsometricTouchOverlay.MouseMove +=
                e =>
                {
                    //var x = e.IsometricPosition.X / (double)DefaultWidth;
                    //Statusbar.Messenger = "x: " + x;
                    //Music.Volume = x;

                    MouseContainer.MoveContainerTo(e.IsometricPosition.X, e.IsometricPosition.Y);

                    if (!TouchInputEnabled)
                    {
                        MouseContainer.City.Hide();
                        MouseContainer.Trees.Hide();
                        return;
                    }

                    //Statusbar.Messenger = new { e.PositionAtAltitude.X, e.PositionAtAltitude.Y }.ToString();

                    var t = e.Tile;
                    if (t != null)
                    {
                        PropertyManager.Selection = PropertyManager[t];

                        MouseContainer.City.Show(PropertyManager.Selection != null);

#if DEBUG
                        MouseContainer.Trees.Show(Builder.Descriptions.GroupOfTreeLand.Contains(t.Description));
#endif

                    }

#if XXDEBUG


					MouseSprite.MoveTo(
                        e.Position.X - Canvas.GetLeft(Playground.Content) ,
                        e.Position.Y - Canvas.GetTop(Playground.Content)
                    );

                    MouseSprite2.MoveTo(
                        e.PositionAtAltitude.X - Canvas.GetLeft(Playground.Content),
                        e.PositionAtAltitude.Y - Canvas.GetTop(Playground.Content)
                   );
#endif
                };

            var EgoAnalytics = new PropertyValueAnalytic();

            IsometricTouchOverlay.MouseLeftButtonUp +=
                e =>
                {
                    if (!TouchInputEnabled)
                        return;

                    var Property = PropertyManager[e.Tile];

                    if (Property != null)
                    {

                        if (Property.Analytic == null)
                        {
                            if (Statusbar.BankAccount < Property.Value)
                            {
                                // http://translate.google.com/translate_t?hl=en&sl=et&tl=en#en|zh-CN|insufficient%20cash
                                //Builder.VisualizeError("现金不足！", e.Tile);
                                // flashgamedistribution suugested to use english afterall...

                                Builder.VisualizeError("no cash!", e.Tile);
                                (KnownAssets.Path.Assets + "/tick.mp3").PlaySound();
                            }
                            else
                            {
                                Property.Analytic = new PropertyValueAnalytic();
                                Builder.VisualizeCost(-Property.Value, e.Tile);

                                (KnownAssets.Path.Assets + "/cash.mp3").PlaySound();
                            }
                        }
                        else
                        {
                            Property.Analytic = null;
                            Builder.VisualizeCost(Property.Value, e.Tile);

                            (KnownAssets.Path.Assets + "/cashout.mp3").PlaySound();
                        }



                        return;
                    }

#if DEBUG
                    if (Builder.Descriptions.GroupOfTreeLand.Contains(e.Tile.Description))
                    {
                        new PlaygroundBuilder.Tree1(e.Tile).SetFrame(0);

                        (KnownAssets.Path.Assets + "/place_tile.mp3").PlaySound();

                        Builder.VisualizeCost(-12, e.Tile);
                    }


                    if (e.Tile.Description == Builder.Descriptions.RoadX)
                    {
                        Builder.AddBusX(e.Tile.X + 0.5, e.Tile.Y - 0.8);
                        return;
                    }
#endif

                };
            #endregion



            #endregion


            var StatusbarMove = NumericEmitter.OfDouble(
                (x, y) => Statusbar.MoveContainerTo(x, y)
            );

            var StatusbarTopOffset = 0.0;

            Action CenterStatusbar = delegate
            {
                StatusbarMove((this.Width - Statusbar.Width) / 2, Height + StatusbarTopOffset);
            };

            CenterStatusbar();

            this.SizeChanged +=
                delegate
                {
                    CenterStatusbar();
                };


            #region instruction menu
            var Shadow = new Rectangle
            {
                Fill = Brushes.Black,
                Opacity = 0.5,
                Width = DefaultWidth,
                Height = DefaultHeight
            }.AttachTo(Instructions);

            this.SizeChanged +=
                delegate
                {
                    Shadow.SizeTo(this.Width, this.Height);
                };


            var Play = new TycoonButton(300, 48)
            {
                Text = "Click to play!\n- or -\nWait and read instructions..."
            }.AttachContainerTo(Instructions);

            var Video = new TycoonButton(400, 200)
            {

            }.AttachContainerTo(Instructions);


            var VideoText = new TycoonButton(400, 48)
            {
                TextAlignment = TextAlignment.Left,
                IsAnimated = true
            }.AttachContainerTo(Instructions);

            Action CenterInstructions = delegate
            {
                Play.MoveContainerTo((this.Width - Play.Width) / 2, 40);
                Video.MoveContainerTo((this.Width - Video.Width) / 2, 96 + 16);
                VideoText.MoveContainerTo((this.Width - Video.Width) / 2, 96 + 16 + 200 + 2);
            };

            CenterInstructions();

            this.SizeChanged +=
                delegate
                {
                    CenterInstructions();
                };

            var Typewriter = new AudioLoop
            {
                Volume = 0.5,

                Enabled = true,
                Loop = (KnownAssets.Path.Assets + "/typewriter.mp3"),

            };

            InitializeVideo(Builder, Video, VideoText);

            var ShadowAnimation = Shadow.ToAnimatedOpacity();
            ShadowAnimation.Opacity = Shadow.Opacity;
            #region gong
            TouchOverlay.MouseLeftButtonUp += delegate
            {

                if (!Typewriter.Enabled)
                    return;

                TouchInputEnabled = true;
                Typewriter.Enabled = false;


                Play.OrphanizeContainer();
                Video.OrphanizeContainer();
                VideoText.OrphanizeContainer();
                //Shadow.Orphanize();

                ShadowAnimation.Opacity = 0.9;

                (KnownAssets.Path.Assets + "/gong.mp3").PlaySound();

                300.AtDelay(
                    delegate
                    {
                        ShadowAnimation.Opacity = 0;


                        1000.AtDelay(
                            delegate
                            {
                                StatusbarTopOffset = -Statusbar.Height;
                                CenterStatusbar();
                            }
                        );
                    }
                );
            };
            #endregion

            #endregion

            1000.AtInterval(
                delegate
                {
                    if (!this.TouchInputEnabled)
                        return;
                    Statusbar.Calendar += 1;
                    //Statusbar.BankAccount += 1;
                }
            );


            //// redefine the ctor to fit our context
            //Func<string, string, string, GameMenu.Option> Option =
            //    (Text, Image, href) =>
            //        new GameMenu.Option
            //        {
            //            Text = "Play " + Text + "!",
            //            Source = (KnownAssets.Path.SocialLinks + "/" + Image + ".png").ToSource(),
            //            Hyperlink = new Uri(href),
            //            MarginAfter = Math.PI / 3
            //        };

            #region SocialLinksMenu
            var ShadowSize = 24;
#if !DEBUG
			var SocialLinksMenu = new Bulldog.Client.Promotion.Controls.GameMenuWithGames(DefaultWidth, DefaultHeight, ShadowSize)
				//{
				//    Option("FreeCell", "Preview_FreeCell",  "http://nonoba.com/zproxy/avalon-freecell"),
				//    Option("Spider Solitaire", "Preview_Spider",  "http://nonoba.com/zproxy/avalon-spider-solitaire"),
				//    Option("Treasure Hunt", "Preview_TreasureHunt",  "http://nonoba.com/zproxy/treasure-hunt"),
				//    Option("FlashMinesweeper:MP", "Preview_Minesweeper", "http://nonoba.com/zproxy/flashminesweepermp"),
				//    Option("Multiplayer Mahjong", "Preview_Mahjong", "http://nonoba.com/zproxy/mahjong-multiplayer"),
				//    Option("Multiplayer SpaceInvaders", "Preview_SpaceInvaders", "http://nonoba.com/zproxy/flashspaceinvaders"),
				//}
				;

			SocialLinksMenu.IdleText = "More games!";
			SocialLinksMenu.AttachContainerTo(this);
#endif
            #endregion

            #region SocialLinks
            var SocialLinks = new GameSocialLinks(this)
			{
                new GameSocialLinksButton { 
				    Source = (KnownAssets.Path.Assets + "/fullscreen-button.png").ToSource(),
				    Width = 32,
				    Height = 32,
                    Click = delegate
                    {
                        if (ToFullscreen != null)
                            ToFullscreen();
				    }
                    
				},
				new GameSocialLinksButton { 
				    Source = (KnownAssets.Path.Assets + "/plus_google.png").ToSource(),
				    Width = 62,
				    Height = 17,
				    Hyperlink = new Uri(Info.AddLink)
				},
				new GameSocialLinksButton { 
					Source = (KnownAssets.Path.Assets + "/tk.png").ToSource(),
					Width = 16,
					Height = 16,
					Hyperlink = new Uri( "http://avalon-tycoon-mansion.tk")
				},
				new GameSocialLinksButton { 
				    Source = (KnownAssets.Path.Assets + "/su.png").ToSource(),
				    Width = 16,
				    Height = 16,
				    Hyperlink = new Uri( "http://www.stumbleupon.com/submit?url=" + Info.Web)
				},
				new GameSocialLinksButton { 
					Source = (KnownAssets.Path.Assets + "/abandonia.png").ToSource(),
					Width = 16,
					Height = 16,
					Hyperlink = new Uri( "http://www.abandonia.com/en/games/240/Transport+Tycoon+Deluxe.html")
				},
			
				new GameSocialLinksButton { 
					Source = (KnownAssets.Path.Assets + "/rss.png").ToSource(),
					Width = 14,
					Height = 14,
					Hyperlink = new Uri( "http://zproxy.wordpress.com")
				}
			};
            #endregion
#if !DEBUG
			SocialLinksMenu.AfterMove +=
				(x, y) =>
				{
					SocialLinks.OffsetY = y + SocialLinksMenu.ContentHeight + ShadowSize;
				};

			SocialLinksMenu.Hide();
#endif
            // javascript needs special zindexing...
            // scriptcorelib could do this for use in the future?
            Panel.SetZIndex(Playground.Container, 1);
            Panel.SetZIndex(Instructions, 2);
            Panel.SetZIndex(LogoContainer, 3);
            Panel.SetZIndex(MouseContainer.Container, 4);
            Panel.SetZIndex(TouchOverlay, 5);
#if !DEBUG
			Panel.SetZIndex(SocialLinksMenu.Container, 6);
#endif
            SocialLinks.Buttons.ForEach(
                (k, i) =>
                {
                    Panel.SetZIndex(k.Image, 7 + i);
                    Panel.SetZIndex(k.Overlay, 7 + i);
                }
            );

            ////Are we ready to distribute?
            //new TycoonButton(DefaultWidth, 24)
            //{
            //    BackgroundVisible = false,
            //    Foreground = Brushes.Yellow,
            //    Text = "This game is under development. Do not distribute."
            //}.AttachContainerTo(LogoContainer);

            Action NextDevelopProperty = null;

            NextDevelopProperty =
                delegate
                {
                    DevelopProperty(Builder, PropertyManager,
                        NextDevelopProperty, ConstructionYard.Where(k => Builder.Descriptions.GroupOfTreeLand.Contains(k.Description)).Random()

                    );
                };

            NextDevelopProperty();


            3000.AtDelay(NextDevelopProperty);
            6000.AtDelay(NextDevelopProperty);
            9000.AtDelay(NextDevelopProperty);
            12000.AtDelay(NextDevelopProperty);
            15000.AtDelay(NextDevelopProperty);


            HQProperty.AnalyticChanged +=
                delegate
                {

                    if (this.SetHighscore != null)
                    {
                        this.SetHighscore(this.Statusbar.Calendar);


                    }

#if !DEBUG
					SocialLinksMenu.ValidateHide = () => false;

					1.AtDelay(
						delegate
						{
							TouchOverlay.MouseLeftButtonUp += delegate
							{
								SocialLinksMenu.Show();
							};
						}
					);
#endif

                    (KnownAssets.Path.Assets + "/yeah.mp3").PlaySound();

                    StatusbarMove((DefaultWidth - Statusbar.Width) / 2, Height);
                    this.SetHighscore = null;

                    TouchInputEnabled = false;
                    ShadowAnimation.Opacity = 0.5;


                    var Congratz = new TycoonButton(340, 48 + 48)
                    {
                        Text = "Cool, you now have the mansion :)\nIt took you only " + this.Statusbar.Calendar + " months...\nNext time around you get to manage some trains!\n\nClick for more games!"
                    }.AttachContainerTo(Instructions);

                    Congratz.MoveContainerTo((DefaultWidth - Congratz.Width) / 2, 90);
                };

        }



        private void DevelopProperty(PlaygroundBuilder Builder, PropertyManager xPropertyManager, Action StartNextSimulation, IsometricContainerTile lot)
        {
            var PossiblePropertyToDevelop = new[]
			{
				// the market should adapt to our funds
				new { PotentialValue = 300, Property = Builder.Descriptions.House5 },
				new { PotentialValue = 350, Property = Builder.Descriptions.House6 },
				new { PotentialValue = 400, Property = Builder.Descriptions.House10 },
				new { PotentialValue = 800, Property = Builder.Descriptions.House7 },
				new { PotentialValue = 850, Property = Builder.Descriptions.House15 },
				new { PotentialValue = 900, Property = Builder.Descriptions.House14 },
				new { PotentialValue = 1300, Property = Builder.Descriptions.House11 },
				new { PotentialValue = 1900, Property = Builder.Descriptions.House12 },
			}.Where(k => (this.Statusbar.BankAccount + 100) * 3 >= k.PotentialValue).Random();

            var MarketPotentialValue = PossiblePropertyToDevelop.PotentialValue;
            var MarketHouse = PossiblePropertyToDevelop.Property;


            // add some randomness to the mix
            MarketPotentialValue += (MarketPotentialValue / 2).Random() - (MarketPotentialValue / 4);

            DevelopProperty(Builder, xPropertyManager, StartNextSimulation, lot, MarketPotentialValue, 0.02, MarketHouse);
        }

        private static void DevelopProperty(PlaygroundBuilder Builder, PropertyManager xPropertyManager, Action StartNextSimulation, IsometricContainerTile lot, double MarketPotentialValue, double MarketSpeed, IsometricContainer.TileDescription MarketHouse)
        {
            var p = new PropertyManager.AvailableProperty(xPropertyManager)
            {
                Tile = lot,
                Value = 0,
            };

            //Console.WriteLine("create: " + new { lot.X, lot.Y }.ToString());

            var MarketAge = -Math.PI / 3;

            //lot.Description = Builder.Descriptions.BuildableHouses.Random();
            lot.Description = MarketHouse;

            p.AnalyticChanged +=
                delegate
                {
                    if (p.Analytic == null)
                    {
                        // force permature aging
                        MarketAge += 2 * Math.PI;
                    }
                };

            (1000 / 20).AtIntervalWithTimer(
                t =>
                {
                    if (MarketAge < (1.5) * Math.PI)
                        MarketAge += MarketSpeed;
                    else
                        // late sellers will experience slow net value increse
                        MarketAge += MarketSpeed * 0.5;

                    p.Value = Convert.ToInt32(Math.Ceiling((Math.Sin(MarketAge) + 1.0) * MarketPotentialValue * 0.5));


                    // we wont sell the property unless its time has come and the agent has gone
                    if (MarketAge > (1.5) * Math.PI)
                        if (p.Analytic == null)
                        {
                            if (lot.Description.Deconstructor != null)
                            {
                                lot.Description = lot.Description.Deconstructor();
                            }
                            else
                            {
                                // clear it
                                lot.Description = Builder.Descriptions.Dirt;
                            }

                            p.Dispose();
                            //Console.WriteLine("dispose: " + new { lot.X, lot.Y }.ToString());

                            // return to market
                            2000.AtDelay(StartNextSimulation);

                            t.Stop();
                        }
                }
            );
        }


        public bool TouchInputEnabled;

        private static void InitializeVideo(PlaygroundBuilder Builder, TycoonButton Video, TycoonButton VideoText)
        {
            var VideoBuilder = new PlaygroundBuilder
            {
                Descriptions = Builder.Descriptions,
                Playground = new IsometricContainer(400 - 8, 200 - 8, 12, 12)
            };

            var VideoMouse = new TycoonMouse().AttachContainerTo(VideoBuilder.Playground.Overlay);
            VideoMouse.Show();

            var VideoMouseMove = NumericEmitter.OfDouble(
                (x, y) => VideoMouse.MoveContainerTo(x, y)
            );
            Action<int, int> VideoMouseMoveToTile =
                (x, y) =>
                {
                    var p = VideoBuilder.Playground.ToIsometricPosition(x + 0.5, y - 0.5);

                    VideoMouseMove(p.X, p.Y);
                };
            VideoMouseMove(0, 0);

            VideoBuilder.Playground.Container.Background = Brushes.Black;
            VideoBuilder.Playground.AttachContainerTo(Video).MoveContainerTo(4, 4);

            VideoBuilder.Playground.Fill(VideoBuilder.Descriptions.Grass);
            VideoBuilder.RoadX(5);
            VideoBuilder.RoadY(4);
            VideoBuilder.AddBusX(5, 4.2);

            Action Video_Step0 =
                delegate
                {

                    4.Times(
                        () =>
                        {
                            VideoBuilder.BuildTree1(VideoBuilder.Playground.Where(k => k.Description == VideoBuilder.Descriptions.Grass).Random());
                        }
                    );

                    VideoBuilder.Playground[6, 4].Description = VideoBuilder.Descriptions.HeadQuarter;

                    VideoBuilder.Playground[5, 7].Description = VideoBuilder.Descriptions.Dirt;

                    VideoText.Text =
                    @"Welcome back, Commander!    
You are now playing Avalon Tycoon Mansion!";


                    300.AtDelay(
                        () => VideoMouseMoveToTile(2, 6)
                    );
                };
            Action Video_Step1 =
                delegate
                {



                    VideoBuilder.Playground[5, 7].Description = VideoBuilder.Descriptions.House5b;

                    VideoText.Text =
                        @"The aim of the game is to make enough money buying and 
selling houses on the property market to buy the mansion.";


                    300.AtDelay(
                        () => VideoMouseMoveToTile(6, 4)
                    );

                };

            Action Video_Step2 =
                delegate
                {
                    //VideoBuilder.Playground.Fill(VideoBuilder.Descriptions.Grass);
                    //VideoBuilder.Playground[6, 4].Description = VideoBuilder.Descriptions.HeadQuarter;
                    //VideoBuilder.RoadX(5);
                    //VideoBuilder.RoadY(4);
                    VideoBuilder.Playground[3, 6].Description = VideoBuilder.Descriptions.Dirt;
                    3000.AtDelay(
                        () => VideoBuilder.Playground[3, 6].Description = VideoBuilder.Descriptions.House5a
                    );
                    VideoBuilder.Playground[5, 7].Description = VideoBuilder.Descriptions.House5c;

                    300.AtDelay(
                        () => VideoMouseMoveToTile(3, 6)
                    );

                    VideoText.Text =
                        @"Buy houses by clicking on them when they come up for 
sale. Remember - you can only buy what you can afford.";


                };

            Action Video_Step3 =
                delegate
                {
                    VideoBuilder.Playground[3, 6].Description = VideoBuilder.Descriptions.House5b;

                    300.AtDelay(
                        () => VideoMouseMoveToTile(5, 7)
                    );

                    VideoText.Text =
                    @"Prices go up and down. Sell at the right time to make 
the most profit. Click on a house to sell it.";

                };

            Action Video_Step4 =
                delegate
                {
                    VideoBuilder.Playground[3, 6].Description = VideoBuilder.Descriptions.House5c;

                    3000.AtDelay(
                        () => VideoBuilder.Playground[3, 6].Description = VideoBuilder.Descriptions.House5x
                    );

                    300.AtDelay(
                        () => VideoMouseMoveToTile(5, 7)
                    );

                    VideoText.Text =
                    @"Some properties are cheaper than others. 
Start small and move in to more expensive areas.";


                };

            Action Video_Step5 =
                delegate
                {
                    VideoBuilder.Playground[3, 6].Description = VideoBuilder.Descriptions.Dirt;


                    300.AtDelay(
                        () => VideoMouseMoveToTile(6, 4)
                    );

                    VideoText.Text =
                    @"Your mission is to aqcuire the mansion.";


                };
            var Video_Steps = new List<Action>
			{
				Video_Step1,
				Video_Step2,
				Video_Step3,
				Video_Step4,
				Video_Step5,
				Video_Step0

			}.ToCyclicAction(h => h());


            (15000).AtInterval(Video_Steps);
            Video_Step0();
        }
    }
}
